using System;
using System.Collections.Generic;
using UnityEngine;

namespace NL.Advanced
{



    public delegate NLIni IniAction<T1, T2>(T1 t1, T2 t2);
    public delegate NLIni IniAction<T1, T2, T3>(T1 t1, T2 t2, T3 t3);

    public delegate List<NLIni> LstIniAction<T>(T t);
    public delegate List<NLIni> LstIniAction<T1, T2>(T1 t1, T2 t2);

    public delegate string StringAction<T1, T2>(T1 t1, T2 t2);
    public delegate string StringAction<T1, T2, T3>(T1 t1, T2 t2, T3 t3);


    public static class IniExtension
    {
        public static T AsEnumer<T>(this nill target, T _default = default(T)) where T : struct
        {
            if (!typeof(T).IsEnum)
            {
                return _default;
            }

            if (!string.IsNullOrEmpty(target.Content) && Enum.TryParse<T>(target.AsString, ignoreCase: true, out var result))
            {
                return result;
            }

            return _default;
        }

        //public static NLIni Copy(this NLIni source)
        //{
        //    return new NLIni(source.ToString(), '\n');
        //}


        /// <summary>
        /// 将 Json字符表达式 转化为 Vector3.
        /// </summary>
        /// <param name="who"></param>
        /// <param name="keys"> 如果需要指定 表示 x,y,z的键值</param>
        /// <returns></returns>

        // {"x":"123", "y":"200"}
        public static Vector3 AsVectorFromJson(this nill who, params string[] keys)
        {
            Vector3 pos = Vector3.zero;

            if (who == null) return pos;



            string s = who.AsString.Replace("{", "").Replace("}", "").Replace("\"", "").Replace(":", "=");

            if (keys != null)
            {
                if (keys.Length > 0 && keys[0].Length > 0)
                    s = s.Replace(keys[0], "x");
                if (keys.Length > 1 && keys[1].Length > 0)
                    s = s.Replace(keys[1], "y");
                if (keys.Length > 2 && keys[2].Length > 0)
                    s = s.Replace(keys[2], "z");
            }


            NLIni ini = new NLIni(s, ',');

            pos = new Vector3(
                ini["x"].AsFloatDefault(0),
                ini["y"].AsFloatDefault(0),
                ini["z"].AsFloatDefault(0)
                );

            return pos;
        }

        /// <summary>
        /// 计算机元年
        /// </summary>
        private static DateTime UNIX_TIME = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);

        public static DateTime AsDateTimeFor_C_Local(this nill who)
        {
            long ticks = (long)who.ToULong();

            TimeSpan ts = TimeSpan.FromSeconds(ticks);

            return UNIX_TIME + ts;

        }

        public static DateTime AsDateTimeFor_C_Local(this string who)
        {
            long ticks = 0;

            if (long.TryParse(who, out ticks))
            {
                TimeSpan ts = TimeSpan.FromSeconds(ticks);
                return UNIX_TIME + ts;
            }
            else
            {
                return UNIX_TIME;
            }
        }
        public static DateTime AsDateTimeFor_C_Local(this long who)
        {
            TimeSpan ts = TimeSpan.FromSeconds(who);
            return UNIX_TIME + ts;
        }

        public static bool ContainsKey(this NLIni ini, string key)
        {
            if (ini == null) return false;
            return ini.AsDictionary.ContainsKey(key);
        }

        public static void SetBool(this NLIni ini, string key, bool b)
        {
            if (ini == null) return;
            ini[key] = b ? bool.TrueString : bool.FalseString;//"True" : "False";
        }

        /// <summary>
        /// 转换为bool值（只有true[无论大小写怎么组合]返回true，其他均为false）
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool ToBool(this nill target)
        {
            //if(target == null) return false;
            bool result = false;

            if (!string.IsNullOrEmpty(target.Content) && bool.TryParse(target.Content, out result))
            {
                return result;
            }

            return false;


            //NLIni ini = new NLIni();

            //ini["BTest"] = "TRUER";
            //bool bt = ini["BTest"].AsBool();
            //Debug.Log($"BTest = {bt}");

            //ini["BTest"] = "True";
            //bt = ini["BTest"].AsBool();
            //Debug.Log($"BTest = {bt}");

            //ini["BTest"] = "true";
            //bt = ini["BTest"].AsBool();
            //Debug.Log($"BTest = {bt}");

            //ini["BTest"] = "trUE";
            //bt = ini["BTest"].AsBool();
            //Debug.Log($"BTest = {bt}");

            //ini["BTest"] = "TrUe";
            //bt = ini["BTest"].AsBool();
            //Debug.Log($"BTest = {bt}");

            //ini["BTest"] = "FALSE";
            //bt = ini["BTest"].AsBool();
            //Debug.Log($"BTest = {bt}");

            //ini["BTest"] = "False";
            //bt = ini["BTest"].AsBool();
            //Debug.Log($"BTest = {bt}");

            //ini["BTest"] = "false";
            //bt = ini["BTest"].AsBool();
            //Debug.Log($"BTest = {bt}");

            //ini["BTest"] = "falSE";
            //bt = ini["BTest"].AsBool();
            //Debug.Log($"BTest = {bt}");
        }

        public static long ToLong(this nill target)
        {
            //if(target == null) return 0;
            long result = 0;
            if (!string.IsNullOrEmpty(target.Content) && long.TryParse(target.Content, out result))
            {
                return result;
            }
            return result;
        }

        /// <summary>
        /// 将一个NLIni列表数据转换为名值对形式的字符串。
        /// </summary>
        /// <param name="target"></param>
        /// <param name="key">数据的key字段（数据必须含有该字段）</param>
        /// <param name="val">数据的value字段（不存时默认为0）</param>
        /// <param name="_interSplit">输出中的数据分隔符（会自动删除末尾的分隔符）</param>
        /// <param name="_outerSplit">输出中的数据分隔符（会自动删除末尾的分隔符）</param>
        /// <returns></returns>
        public static string ToKeyValueString(this List<NLIni> target, string key, string val, char _interSplit = '=', char _outerSplit = ';')
        {
            if (target == null) return null;
            string info = "";
            //foreach (var data in target)
            target.ForEach(data =>
            {
                if (data.ContainsKey(key))
                {
                    if (data.ContainsKey(val))
                        info += $"{data[key]}{_interSplit}{data[val]}{_outerSplit}";
                    else
                        info += $"{data[key]}{_interSplit}0{_outerSplit}";
                }
            });
            if (!string.IsNullOrEmpty(info))
                if (info.LastIndexOf(_outerSplit) == info.Length - 1)
                    info = info.Substring(0, info.Length - 1);

            return info;
        }

        /// <summary>
        /// 统计功能：将一个kv结构的属性内容解析并记录到recordIni中。
        /// </summary>
        /// <param name="ini"></param>
        /// <param name="key"></param>
        /// <param name="_interSplit"></param>
        /// <param name="_outerSplit"></param>
        /// <param name="recordIni"></param>
        /// <returns></returns>
        public static bool RecordKeyValueParam(this NLIni ini, string key, char _interSplit, char _outerSplit, ref NLIni recordIni)
        {
            if (ini == null) return false;
            if (recordIni != null && ini != null && ini.ContainsKey(key))
            {
                //sold
                var kvs = StringTools.KeyValuePairs(ini[key].AsString, _outerSplit, _interSplit);
                if (kvs != null && kvs.Length > 0)
                {
                    int tmpV;
                    foreach (var kv in kvs)
                    {
                        if (!recordIni.ContainsKey(kv.Key))
                        {
                            recordIni[kv.Key] = kv.Value;
                        }
                        else
                        {
                            if (int.TryParse(kv.Value, out tmpV))
                            {
                                recordIni[kv.Key] = recordIni[kv.Key].AsIntDefault() + tmpV;
                            }
                        }
                    }

                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 统计目标ini数据中的数字属性（target->record）
        /// </summary>
        /// <param name="recordIni"></param>
        /// <param name="targetIni"></param>
        /// <param name="add"></param>
        /// <param name="allProps"></param>
        /// <returns></returns>
        static bool _RecordNumProperties(this NLIni recordIni, NLIni targetIni, bool add = true, bool allProps = true)
        {
            if (recordIni == null) return false;
            if (recordIni != null && targetIni != null)
            {
                bool changed = false;
                float tmpNum;
                foreach (KeyValuePair<string, nill> item in targetIni.AsDictionary)
                {
                    if (!string.IsNullOrEmpty(item.Key))
                    {
                        if (float.TryParse(item.Value, out tmpNum))
                        {
                            if (recordIni.ContainsKey(item.Key))
                            {
                                recordIni[item.Key] = recordIni[item.Key].AsFloatDefault() + (add ? tmpNum : -tmpNum);
                                changed = true;
                            }
                            else if (allProps)
                            {
                                recordIni[item.Key] = (add ? tmpNum : -tmpNum);
                                changed = true;
                            }
                        }
                    }
                }

                return changed;
            }

            return false;
        }

        /// <summary>
        /// 统计目标ini数据中的数字属性（target->record）
        /// </summary>
        /// <param name="recordIni"></param>
        /// <param name="targetIni"></param>
        /// <param name="allProps"></param>
        /// <returns></returns>
        public static bool RecordNumProperties(this NLIni recordIni, NLIni targetIni, bool allProps = true)
        {
            return recordIni._RecordNumProperties(targetIni, true, allProps);
        }

        public static bool RecordNumProperties(this NLIni recordIni, string propertyStr, string split = "", bool add = true, bool allProps = true)
        {
            if (recordIni != null && !string.IsNullOrEmpty(propertyStr))
            {
                char splitChar = NLConst.CHAR_ARRAY;
                if (!string.IsNullOrEmpty(split))
                    splitChar = split.ToCharArray()[0];
                
                var targetIni = new NLIni(propertyStr, splitChar);

                return recordIni._RecordNumProperties(targetIni, add, allProps);
            }

            return false;
        }


        /// <summary>
        /// 解析国王详情的数据
        /// </summary>
        /// <param name="recordIni"></param>
        /// <param name="targetIni"></param>
        /// <param name="allProps"></param>
        /// <returns></returns>
        public static bool RecordNumPropertiesOnMecha(this NLIni recordIni, NLIni targetIni, bool allProps = true)
        {
            if (recordIni != null && targetIni != null)
            {
                bool changed = false;
                float tmpNum;
                foreach (KeyValuePair<string, nill> item in targetIni.AsDictionary)
                {
                    if (!string.IsNullOrEmpty(item.Key))
                    {
                        if (float.TryParse(item.Value, out tmpNum))
                        {
                            if (recordIni.ContainsKey(item.Key))
                            {
                                recordIni[item.Key] = recordIni[item.Key].AsFloatDefault() + tmpNum;
                                changed = true;
                            }
                            else if (allProps)
                            {
                                recordIni[item.Key] = tmpNum;
                                changed = true;
                            }
                        }
                    }
                }

                return changed;
            }

            return false;
        }


        /// <summary>
        /// 统计两个Ini对象中的数字属性（以srcIni为主）
        /// </summary>
        /// <param name="srcIni"></param>
        /// <param name="trgIni"></param>
        /// <param name="recordIni"></param>
        /// <param name="trgAll">是否是全部属性。为false时，只记录srcIni含有的属性</param>
        /// <returns></returns>
        public static bool RecordNumProperties(NLIni srcIni, NLIni trgIni, out NLIni recordIni, bool trgAll = true)
        {
            recordIni = new NLIni();
            if (srcIni == null || trgIni == null)
            {
                if (srcIni != null)
                {
                    recordIni.Add(srcIni);
                    return true;
                }
                else if (trgIni != null && trgAll)
                {
                    recordIni.Add(trgIni);
                    return true;
                }
            }
            else
            {
                recordIni.Add(srcIni);
                return recordIni.RecordNumProperties(trgIni, trgAll);
            }
            return false;
        }

        //this List<T> lst, string key, nill value) where T : NLIni
        public static NLIni ListToIniData<T>(this List<T> lst, string idKey, string valKey, bool isSum = true) where T : NLIni
        {
            NLIni ini = new NLIni();
            bool _isSum = isSum;
            if (lst != null && !string.IsNullOrEmpty(idKey))
            {
                for (int i = 0; i < lst.Count; i++)
                {
                    var elm = lst[i];
                    if (elm != null && elm.ContainsKey(idKey))
                    {
                        string key = elm[idKey].AsString;
                        if (_isSum && long.TryParse(elm[valKey], out long kval))
                        {
                            ini[key] = ini[key].ToLong() + kval;
                        }
                        else
                        {
                            _isSum = false;

                            if (i == 0)
                                ini[key] = elm[valKey];
                            else
                                ini[key] = ini[key] + "," + elm[valKey];
                        }
                    }
                }
            }
            return ini;
        }

        /// <summary>
        /// 判断两个NLIni指定keys的值是否相同
        /// </summary>
        /// <param name="ini"></param>
        /// <param name="other"></param>
        /// <param name="keys"></param>
        /// <returns></returns>
        public static bool EqualsKeys(this NLIni ini, NLIni other, params string[] keys)
        {
            if (ini == null || other == null)
                return false;

            if (keys != null && keys.Length > 0)
            {
                bool valid = false;
                foreach (string key in keys)
                {
                    if (!string.IsNullOrEmpty(key))
                    {
                        valid = true;
                        if (ini.ContainsKey(key) && other.ContainsKey(key))
                        {
                            if (!ini[key].Equals(other[key]))
                                return false;
                        }
                        else
                        {
                            return false;
                        }
                    }
                }

                return valid;
            }
            return false;
        }

        /// <summary>
        /// 获取数据别名对应的值。别名列表按照先后顺序寻找，直到有值为止。
        /// </summary>
        /// <param name="ini"></param>
        /// <param name="aliasKeys"></param>
        /// <returns></returns>
        public static nill AliasValue(this NLIni ini, params string[] aliasKeys)
        {
            if (ini != null)
                if (aliasKeys != null && aliasKeys.Length > 0)
                    foreach (string key in aliasKeys)
                        if (!string.IsNullOrEmpty(key))
                            if (ini.ContainsKey(key))
                                return ini[key];

            return default(nill);
        }


        public static bool CopyKeysWithPreFix(this NLIni ini, NLIni other, string _prefix, params string[] keys)
        {
            if (keys != null && keys.Length > 0)
            {
                foreach (string key in keys)
                {
                    if (!string.IsNullOrEmpty(key))
                    {
                        if (other.ContainsKey(key))
                            ini[_prefix + key] = other[key];
                        //else
                        //    ini[_prefix + key] = default(nill);
                    }
                }
            }
            return true;
        }

        public static bool CopyKeys(this NLIni ini, NLIni other, params string[] keys)
        {
            return CopyKeysWithPreFix(ini, other, "", keys);
        }

        /// <summary>
        /// 生成一个只含部分信息的Ini
        /// </summary>
        /// <param name="ini"></param>
        /// <param name="keys">需要包含的key列表</param>
        /// <returns></returns>
        public static NLIni ToSubIni(this NLIni ini, params string[] keys)
        {
            NLIni subIni = new NLIni();
            if (keys != null && keys.Length > 0)
                subIni.CopyKeys(ini, keys);
            else
                subIni.Add(ini);
            return subIni;
        }

        /// <summary>
        /// 生成一个不包含某些属性的Ini
        /// </summary>
        /// <param name="ini"></param>
        /// <param name="withoutKeys"></param>
        /// <returns></returns>
        public static NLIni ToSubIniWithoutKeys(this NLIni ini, params string[] withoutKeys)
        {
            if (ini == null)
                return ini;

            NLIni subIni = new NLIni();
            if (withoutKeys != null && withoutKeys.Length > 0)
            {
                foreach (KeyValuePair<string, nill> item in ini.AsDictionary)
                {
                    if (!string.IsNullOrEmpty(item.Key) && Array.IndexOf(withoutKeys, item.Key) < 0)
                    {
                        subIni[item.Key] = item.Value;
                    }
                }
            }
            else
                subIni.Add(ini);

            return subIni;
        }

        public static int IndexOfKey(this List<NLIni> lst, string key, nill value)
        {
            if (lst != null && !string.IsNullOrEmpty(key))
            {
                for (int i = 0; i < lst.Count; i++)
                {
                    NLIni elm = lst[i];
                    if (elm != null && elm.ContainsKey(key))
                    {
                        if (elm[key].AsString == value.AsString)
                        {
                            return i;
                        }
                    }
                }
            }
            return -1;
        }

        public static int IndexOfKey<T>(this List<T> lst, string key, nill value) where T : NLIni
        {
            if (lst != null && !string.IsNullOrEmpty(key))
            {
                for (int i = 0; i < lst.Count; i++)
                {
                    NLIni elm = lst[i];
                    if (elm != null && elm.ContainsKey(key))
                    {
                        if (elm[key].AsString == value.AsString)
                        {
                            return i;
                        }
                    }
                }
            }
            return -1;
        }

        public static T FindElementByKey<T>(this List<T> lst, string key, nill value) where T : NLIni
        {
            int index = lst.IndexOfKey(key, value);
            if (index >= 0)
            {
                return lst[index];
            }
            return null;
        }

        public static List<NLIni> TOIniList<T>(this List<T> lst) where T : NLIni
        {
            List<NLIni> iniLst = new List<NLIni>();
            if (lst != null)
                iniLst.AddRange(lst);
            return iniLst;
        }

        public static Vector4 AsVector4(this nill target, char _char = ';')
        {
            List<nill> list = target.AsArray(_char);
            if (list == null || list.Count < 1)
            {
                return Vector4.zero;
            }

            return new Vector4((list.Count > 0) ? list[0].AsFloat : 0f, (list.Count > 1) ? list[1].AsFloat : 0f, (list.Count > 2) ? list[2].AsFloat : 0f, (list.Count > 3) ? list[3].AsFloat : 0f);
        }
    }
}